package org.mozhu.zufang.wechat.wx.message;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.logging.log4j.util.Strings;
import org.mozhu.zufang.wechat.wx.WechatProperties;
import org.mozhu.zufang.wechat.wx.model.Message;
import org.mozhu.zufang.wechat.wx.model.MessageContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import javax.xml.bind.JAXBContext;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Collections;
import java.util.List;

@RestController
@RequestMapping("/message")
@Slf4j
public class MessageController {
    private Logger streamlog = LoggerFactory.getLogger("http.StreamLog.wechat.message");
    @Autowired
    WechatProperties wechatProperties;

    @Autowired
    ApplicationContext applicationContext;

    @RequestMapping(method = RequestMethod.GET)
    String verify(@RequestParam(value = "signature") String signature, @RequestParam String timestamp, @RequestParam String nonce, @RequestParam String echostr) {
        String token = wechatProperties.getToken();
        List<String> strings = Lists.newArrayList(token, timestamp, nonce);
        Collections.sort(strings);
        String string = Joiner.on("").join(strings);
        String calSignature = DigestUtils.sha1Hex(string);
        log.info("InputSignature=> {}, timestamp=> {}, nonce=> {}, echostr=>{}", signature, timestamp, nonce, echostr);
        log.info("OutputSignature=> {}", calSignature);
        if (signature.equals(calSignature)) {
            return echostr;
        }
        return Strings.EMPTY;
    }

    @RequestMapping(method = RequestMethod.POST, produces = MediaType.TEXT_XML_VALUE)
    Message receive(@RequestParam(required = false) String signature, @RequestParam(required = false) String timestamp, @RequestParam(required = false) String nonce, @RequestParam(value = "encrypt_type", required = false) String encryptType, @RequestParam(value = "msg_signature", required = false) String msgSignature, @RequestBody String request) {
        if (streamlog.isInfoEnabled()) {
            streamlog.info("Receive message <<| {}", request);
        }

        if (wechatProperties.isMessageVerify()) {
            String echostr = "123";
            if (!echostr.equals(verify(signature, timestamp, nonce, echostr))) {
                throw new IllegalArgumentException("Invalid signature");
            }
        }
        try {
            Message message = (Message) JAXBContext.newInstance(Message.class).createUnmarshaller().unmarshal(new StringReader(request));
            MessageContext.put(new MessageContext(message.getFrom(), message));
            String from = message.getFrom();
            String to = message.getTo();

//            if (message.getType() != null) {
//                Yaml yaml = new Yaml();
//                def configuration = yaml.load(new InputStreamReader(MessageController.class.getClassLoader().getResourceAsStream("wechat.yaml"), "UTF-8"));
//                def handler = find(configuration.handlers, message);
//                def result = [type:
//                "text", content:"请输入帮助命令: help"];
//                if (handler != null) {
//                    result = invoke(message, handler.params, handler.service);
//                }
//
//                if (result.properties != null) {
//                    InvokerHelper.setProperties(message, result.properties);
//                } else {
//                    result.each {
//                        name, value ->
//                                message[name] = value;
//                    }
//                }
//            }

            message.setFrom(to);
            message.setTo(from);

            StringWriter writer = new StringWriter();
            JAXBContext.newInstance(Message.class).createMarshaller().marshal(message, writer);
            String responseMessage = writer.toString();
            if (streamlog.isInfoEnabled()) {
                streamlog.info("Return message >>| {}", responseMessage);
            }
            return message;
        } catch (Exception e) {
            log.error("Process message failed", e);
        } finally {
            MessageContext.remove();
        }
        return null;
    }

//    Object invoke(Message message, params, String serviceText) {
//        String[] beanAndMethods = serviceText.trim().split("\\.");
//        Object bean = applicationContext.getBean(beanAndMethods[0]);
//        Map result = Maps.newHashMap();
//        if (beanAndMethods.length >= 2) {
//            result = bean."${beanAndMethods[1]}" (params);
//        } else {
//            result = bean.invoke(params);
//        }
//        return result;
//    }
//
//    def find(handlers, message) {
//        def params = [];
//        def handler = handlers.find {
//            item ->
//            boolean notMatch = false;
//            for (entry in item.matchers.entrySet()) {
//                def name = entry.key;
//                def patternText = entry.value;
//                if (message[name] == null && patternText == "null") {
//                    continue;
//                }
//
//                def pattern = Pattern.compile(patternText);
//                def matcher = pattern.matcher(String.valueOf(message[name]));
//                if (!matcher.matches()) {
//                    notMatch = true;
//                    params = [];
//                    break;
//                }
//
//                for (int i = 0; i < matcher.groupCount(); i++) {
//                    params.add(matcher.group(i + 1));
//                }
//            }
//
//            if (!notMatch) {
//                return true;
//            }
//            return false;
//        }
//
//        if (handler == null) {
//            return null;
//        }
//
//        return [params:
//        params, service:handler.service];
//    }
}
